﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace CarCricketMatchApp
{
    /// <summary>
    /// Team to batting for match,
    /// 
    /// </summary>
    public class Team
    {
        /// <summary>
        /// each team contains 11 player
        /// </summary>
        private const int MAXACCOUNT = 11;

        
       
        #region private variable
        private Inns inning;
        private ArrayList players;
        private ArrayList outPlayers;
        private string name;
        private int currentOrder = 1;
        private int extraScore;

     
        #endregion

        #region properties

        /// <summary>
        /// get the inning of team
        /// </summary>
        public Inns Inning
        {
            get { return inning; }
        }

        /// <summary>
        /// get and set the players of team
        /// </summary>
        public ArrayList Players
        {
            get { return players; }
            set { players = value; }
        }

        /// <summary>
        /// get and set the out players of team
        /// </summary>
        public ArrayList OutPlayers
        {
            get { return outPlayers; }
        }

        /// <summary>
        /// get and set the name of team
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        /// <summary>
        /// get and set the current order of team
        /// </summary>
        public int CurrentOrder
        {
            get { return currentOrder; }
        }

        /// <summary>
        /// get and set the extra score
        /// </summary>
        public int ExtraScore
        {
            get { return extraScore; }
            set { extraScore = value; }
        }

        #endregion
        public Team(string name)
        {
            this.name = name;
            players = new ArrayList();
            outPlayers = new ArrayList();
            inning = Inns.In;
            extraScore = 0;
        }

       /// <summary>
       ///  check the player order
       /// </summary>
        public void checkThePlayerOrder()
        {
            // get the all player order
            int[] orders = new int[MAXACCOUNT];
            for(int i=0;i < MAXACCOUNT;i ++)
            {
                orders[i] = (this.players[i] as Player).OrderIndex;
            }

            // sequence the array

            for (int j = 0; j < MAXACCOUNT; j++)
            {
                for (int k = 0; k < MAXACCOUNT; k++)
                {
                    if (orders[k] > orders[j])
                    {
                        int temp = orders[k];
                        orders[k] = orders[j];
                        orders[j] = temp;
                    }
                }
            }
            // get the max and min
            int min = orders[0];
            int max = orders[MAXACCOUNT - 1];
            if ((min == 1) && (max == 11))
            {
                //
            }
            else
            { 
                //
                throw new Exception("Order must be 1 to 11");
            }
            //set the order reduce 1
            int[] newOrders = new int[MAXACCOUNT];
            for (int j = 0; j < MAXACCOUNT; j++)
            {
                newOrders[j] = orders[j] - 1;
            }

            int result = hasDuplicate(newOrders, MAXACCOUNT);
            if (0 == result)
            {
 
            }else if(1 == result)
            {
                throw new Exception("Duplicate order");
            }
        }

        /// <summary>
        /// if the array is duplicate
        /// </summary>
        /// <param name="a">array</param>
        /// <param name="n">array length</param>
        /// <returns>0, false; 1, true </returns>
        private int hasDuplicate(int[] a, int n)
        {
            for (int i = 0; i < n; ++i)
            {
                while (a[i] != i && a[i] != -1)
                {
                    if (a[a[i]] == -1)
                        return 1;
                    a[i] = a[a[i]];
                    a[a[i]] = -1;
                }
                if (a[i] == i)
                {
                    a[i] = -1;
                }
            }
            return 0;
        }

        /// <summary>
        /// add the player to the out players
        /// </summary>
        /// <param name="player"></param>
        public void addPlayerToOutTheTeam(Player player)
        {
            if (this.outPlayers.Count == MAXACCOUNT - 1)
            {
                this.inning = Inns.CompleteIn;
            }
            if (player.Status != States.Out)
            {
                player.Status = States.Out;               
            }
            this.outPlayers.Add(player);
        }

        /// <summary>
        /// add the player to the team
        /// </summary>
        /// <param name="player"></param>
        public void addPlayerToTheTeam(Player player)
        {
            // if the player is full, do not add
            if (this.players.Count == MAXACCOUNT)
            {
                throw new Exception("Team is full");
            }
            //if player is already exist,do not add
            foreach (Player item in this.players)
            {
                if (item.PlayerName == player.PlayerName)
                {
                    throw new Exception("Player is already in the team,please select new one");
                }
            }
            int index = this.players.Add(player);
            //when in, add the players inncout
            player.Inningscount = player.Inningscount + 1;
            player.OrderIndex = index;

        }

        /// <summary>
        /// delete player by index
        /// </summary>
        /// <param name="index"></param>
        public void deletePlayerByIndex(int index)
        {
            if(index< 0 || index >= MAXACCOUNT )
            {
                throw new Exception("Index is out of memory");
            }
            try
            {
                this.players.RemoveAt(index);
                //reset the player index
                // do not reset the player index
                //for (int i = 0, lenght = this.players.Count; i < lenght; i++)
                //{
                //    ((Player)this.players[i]).OrderIndex = i;
                //}
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// get player by name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Player getPlayerByName(string name)
        {
            foreach (Player item in this.players)
            {
                if (item.PlayerName == name)
                    return item;
            }
            return null;
        }
        /// <summary>
        /// get the current order player,set to the actie 
        /// </summary>
        /// <returns></returns>
        public Player getOrderPlayer()
        {
             Player activePlayer = null;
            try
            {
                if (this.outPlayers.Count == MAXACCOUNT - 1)
                {
                    this.inning = Inns.CompleteIn;
                }

                //// set the last player to the out players array
                if (this.currentOrder != 1)
                {
                    if (this.currentOrder >= MAXACCOUNT - 1)
                    {
                        this.inning = Inns.CompleteIn;
                        return null;
                    }
                    //Player obj = (Player)this.players[this.currentOrder - 1];
                    Player obj = this.getPlayerByOrderIndex(this.currentOrder - 1);
                    if (obj != null)
                    {
                        //if not out, use again
                        if (obj.Status != States.Out)
                            return obj;
                        else if (obj.Status == States.Out)
                        {
                            //next player
                            // if it is the last order, set the inning
                            if (this.currentOrder >= MAXACCOUNT -1)
                            {
                                this.inning = Inns.CompleteIn;
                                return null;
                            }
                            activePlayer = this.getPlayerByOrderIndex(this.currentOrder);
                            //set the active
                            activePlayer.Status = States.Active;
                            // set the init score is 0
                            activePlayer.CurrentScore = 0;
                            activePlayer.LastScore = 0;

                            //order index ++
                            currentOrder += 1;
                            return activePlayer;
                        }
                        
                    }

                } else
                {
                    activePlayer = this.getPlayerByOrderIndex(this.currentOrder);
                    //
                    //set the active
                    activePlayer.Status = States.Active;
                    // set the init score is 0
                    activePlayer.CurrentScore = 0;
                    activePlayer.LastScore = 0;

                    //order index ++
                    currentOrder += 1;
                }

                
            }
            catch (Exception exp)
            {
                throw exp;
            }
            
            return activePlayer;
        }

        private Player getPlayerByOrderIndex(int index)
        {
            foreach (Player item in this.players)
            {
                if (item.OrderIndex == index)
                    return item;
            }
            return null;
        }
        /// <summary>
        /// get the score of team when complete in
        /// </summary>
        /// <returns>scores</returns>
        public int getTeamScore()
        {
            int sum = 0;
            foreach (Player player in players)
            {
                sum += player.LastScore;
            }
            // add the extra score 
            sum += extraScore;
            return sum;
        }

        /// <summary>
        /// is exist the player 
        /// </summary>
        /// <returns></returns>
        public bool isExistPlayer(Player player)
        {
            //if player is already exist,do not add
            foreach (Player item in this.players)
            {
                if (item.PlayerName == player.PlayerName)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        ///  if restart the game
        /// </summary>
        /// <returns></returns>
        public bool isRestart()
        {
            return this.outPlayers.Count > 0;
        }

    }
}
